package com.jay.media.music.core

import android.annotation.SuppressLint
import android.content.Intent
import android.media.MediaMetadata
import android.media.browse.MediaBrowser
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.Build
import android.os.Bundle
import android.os.ResultReceiver
import android.service.media.MediaBrowserService
import android.util.Log
import androidx.annotation.RequiresApi
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.Utils
import com.jay.media.kit.LogHelper
import com.jay.media.music.core.constant.Actions
import com.jay.media.music.core.constant.Keys
import com.jay.media.music.core.constant.MusicListType
import com.jay.media.music.core.db.Music
import com.jay.media.music.core.db.MusicManager
import com.jay.media.music.core.notification.MusicCmdConstants
import com.jay.media.music.core.notification.PlayingNotification
import com.jay.media.music.core.notification.PlayingNotificationImpl
import com.jay.media.music.core.player.MusicPlayListener
import com.jay.media.music.core.player.MusicPlayManager
import com.jay.media.music.core.provider.MusicIDHelper
import com.jay.media.music.core.util.MusicExt.toMusic


class MusicService : MediaBrowserService() {

    val TAG = LogHelper.makeLogTag(this::class.java)

    private lateinit var mMediaSession: MediaSession

    private var mCallback: MediaSession.Callback = object : MediaSession.Callback() {
        @SuppressLint("WrongConstant")
        override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) {
            super.onPlayFromMediaId(mediaId, extras)
            Log.d(TAG, "onPlayFromMediaId() called with: mediaId = $mediaId, extras = $extras")

            mediaId?.let {
                MusicPlayManager.get().play(mediaId)
            }
        }

        @SuppressLint("WrongConstant")
        override fun onPrepare() {
            super.onPrepare()
            Log.d(TAG, "onPrepare")
        }

        override fun onPlay() {
            super.onPlay()
            Log.d(TAG, "onPlay")
            MusicPlayManager.get().play()
        }

        override fun onPause() {
            super.onPause()
            Log.d(TAG, "onPause")
            MusicPlayManager.get().pause()
        }

        override fun onSkipToPrevious() {
            super.onSkipToPrevious()
            Log.d(TAG, "onSkipToPrevious")
            MusicPlayManager.get().prev()
        }

        override fun onSkipToNext() {
            super.onSkipToNext()
            Log.d(TAG, "onSkipToNext")
            MusicPlayManager.get().next()
        }

        override fun onSeekTo(pos: Long) {
            super.onSeekTo(pos)
            Log.d(TAG, "onSeekTo $pos")
            MusicPlayManager.get().seekTo(pos)
        }

        override fun onCommand(command: String, args: Bundle?, cb: ResultReceiver?) {
            super.onCommand(command, args, cb)
            LogHelper.d(TAG, "onCommand() called with: command = $command, args = $args, cb = $cb")
        }

        override fun onCustomAction(action: String, extras: Bundle?) {
            super.onCustomAction(action, extras)
            LogHelper.d(TAG, "onCustomAction() called with: action = $action, extras = $extras")
            when (action) {
                Actions.ACTION_QUERY_MUSIC_LIST -> {
                    val type = extras?.getInt(MusicListType.TYPE_KEY, MusicListType.TYPE_PLAY_LIST)
                        ?: MusicListType.TYPE_PLAY_LIST
                    val musicList = ArrayList<Music>()
                    when (type) {
                        MusicListType.TYPE_PLAY_LIST -> {
                            val list = MusicPlayManager.get().getPlayList().map { m -> m.toMusic() }
                            musicList.addAll(list)
                        }
                        MusicListType.TYPE_FAVOR_LIST -> {
                            musicList.addAll(MusicManager.get().queryFavorList())
                        }
                        MusicListType.TYPE_PLAY_HISTORY -> {
                            musicList.addAll(MusicManager.get().queryPlayHistory())
                        }
                        else -> {

                        }
                    }
                    val bundle = Bundle()
                    bundle.putInt(MusicListType.TYPE_KEY, type)
                    bundle.putString(Keys.KEY_MUSIC_LIST, GsonUtils.toJson(musicList))
                    mMediaSession.sendSessionEvent(Actions.ACTION_QUERY_MUSIC_LIST, bundle)
                }
                Actions.ACTION_OPERATE_FAVOR -> {
                    val favor = extras?.getBoolean(Keys.KEY_OPERATE_FAVOR_TYPE, true)
                        ?: true
                    val musicId = extras?.getString(Keys.KEY_MUSIC_ID)
                    MusicPlayManager.get().operateFavor(musicId, favor)
                }
                Actions.ACTION_OPERATE_PLAY_LIST -> {
                    val add = extras?.getBoolean(Keys.KEY_OPERATE_PLAY_LIST_TYPE, true)
                        ?: true
                    val musicId = extras?.getString(Keys.KEY_MUSIC_ID)
                    musicId?.also {
                        if (add) {
                            MusicPlayManager.get().addPlayList(musicId)
                        } else {
                            MusicPlayManager.get().removePlayList(musicId)
                        }
                    }
                }
                else -> {
                }
            }
        }
    }

    private var mMusicPlayListener: MusicPlayListener = object : MusicPlayListener {
        override fun onMediaMetadataChange(media: MediaMetadata?) {
            mMediaSession.setMetadata(media)
        }

        override fun onPlaybackStateChange(state: PlaybackState) {
            mMediaSession.setPlaybackState(state)
        }

        override fun onMediaMetadataListChange(media: List<MediaMetadata>) {
        }
    }

    @RequiresApi(Build.VERSION_CODES.N)
    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "onCreate")
        MusicManager.get().init(this)
        Utils.init(this.application)
        MusicPlayManager.get().init(this)
        MusicPlayManager.get().registerPlayCallBack(mMusicPlayListener)

        initNotification()

        mMediaSession = MediaSession(this, TAG)
        mMediaSession.setCallback(mCallback)
        sessionToken = mMediaSession.sessionToken
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when (intent?.action) {
            MusicCmdConstants.Action.NEXT -> {
                MusicPlayManager.get().next()
            }
            MusicCmdConstants.Action.PLAYORPAUSE -> {
                MusicPlayManager.get().playOrPause()
            }
            MusicCmdConstants.Action.REWIND -> {
                MusicPlayManager.get().prev()
            }
            else -> {
            }
        }
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        MusicPlayManager.get().unregisterPlayCallBack(mMusicPlayListener)
        super.onDestroy()
    }

    override fun onGetRoot(
        clientPackageName: String,
        clientUid: Int,
        rootHints: Bundle?
    ): BrowserRoot? {
        LogHelper.d(
            TAG,
            "onGetRoot() called with: clientPackageName = $clientPackageName, clientUid = $clientUid, rootHints = $rootHints"
        )
        val bundle = Bundle()
        bundle.putInt(Keys.KEY_AUDIO_SESSION_ID, MusicPlayManager.get().getAudioSessionId())
        return BrowserRoot(MusicIDHelper.MEDIA_ROOT_ID, bundle)
    }

    override fun onLoadChildren(
        parentId: String,
        result: Result<MutableList<MediaBrowser.MediaItem>>
    ) {
        LogHelper.d(TAG, "onLoadChildren() called with: parentId = $parentId, result = $result")
        result.sendResult(MusicPlayManager.get().getChildren(parentId))
    }

    private var playingNotification: PlayingNotification? = null

    private fun initNotification() {
        this.playingNotification = PlayingNotificationImpl()
        this.playingNotification?.init(this)
    }
}